#include "serialPort.h"

#include <string.h>
#include <sys/ioctl.h>

serialPort::serialPort() { fd = -1; }

bool serialPort::OpenPort(const char *dev, speed_t speed)
{
    struct termios tty;

    memset(&tty, 0, sizeof(tty));

    // 打开串口
    fd = open(dev, O_RDWR);

    if (fd < 0)
    {
        printf("无法打开串口.\n");
        return -1;
    }

    // 设置串口属性
    if (tcgetattr(fd, &tty) != 0)
    {
        printf("无法获取串口属性.\n");
        close(fd);
        return -1;
    }

    // 设置串口波特率
    cfsetospeed(&tty, speed);
    cfsetispeed(&tty, speed);

    // 设置其他串口参数
    tty.c_cflag &= ~PARENB;  // 无奇偶校验
    tty.c_iflag &= ~INPCK;
    tty.c_cflag &= ~CSTOPB;  // 一个停止位
    tty.c_cflag &= ~CSIZE;
    tty.c_cflag |= CS8;             // 8位数据位
    tty.c_cflag |= CREAD | CLOCAL;  // 开启接收器并忽略控制线

    tty.c_iflag &=
        ~(IGNBRK | IGNCR | INLCR | ICRNL | IUCLC | IXANY | IXON | IXOFF | INPCK | ISTRIP);
    tty.c_iflag |= (BRKINT | IGNPAR);
    tty.c_oflag &= ~OPOST;
    tty.c_lflag &= ~(XCASE | ECHONL | NOFLSH);
    tty.c_lflag &= ~(ICANON | ISIG | ECHO);
    tty.c_cflag |= (CLOCAL | CREAD);

    // 设置超时参数
    fcntl(fd, F_SETFL, 0);  // 0 使能阻塞功能 1关闭
    tty.c_cc[VMIN] = 0;     // 读取的最小字节数
    tty.c_cc[VTIME] = 1;    // 读取超时时间（以0.1秒为单位）

    tcflush(fd, TCIFLUSH);

    // 应用设置
    if (tcsetattr(fd, TCSANOW, &tty) != 0)
    {
        printf("无法设置串口属性.\n");
        close(fd);
        return -1;
    }

    return true;
}

bool serialPort::setbaudrate(speed_t speed)
{
    // 设置串口属性
    struct termios tty;
    if (tcgetattr(fd, &tty) != 0)
    {
        printf("无法获取串口属性.\n");
        close(fd);
        return -1;
    }

    cfsetospeed(&tty, speed);
    cfsetispeed(&tty, speed);

    // 应用设置
    if (tcsetattr(fd, TCSANOW, &tty) != 0)
    {
        printf("无法设置串口属性.\n");
        close(fd);
        return -1;
    }

    return true;
}

void serialPort::rs485_ctl(int rw)
{
    int status = 0;
    if (rw == 1)  // 写数据
    {
        ioctl(fd, TIOCMGET, &status);
        status &= ~TIOCM_RTS;  // 设置RTS信号
        ioctl(fd, TIOCMSET, &status);
    }
    else
    {
        ioctl(fd, TIOCMGET, &status);
        status |= TIOCM_RTS;  // 设置RTS信号
        ioctl(fd, TIOCMSET, &status);
    }
}

int serialPort::readBuffer(uint8_t *buf, int len)
{
    int ret = read(fd, (char *)buf, len);

    // if(ret>0){
    //     printf("recv buf:");
    //     for(uint8_t i=0;i<len;i++)
    //         printf("%02x",*(buf+i));
    //     printf("\n");
    // }else{
    //     printf("recv buf: none\n");
    // }

    return ret;
}

int serialPort::writeBuffer(uint8_t *buf, int len)
{
    // if(len<=15){
    //     printf("send buf:");
    //     uint8_t i=0;
    //     for(i=0;i<len;i++){
    //         printf("%02x ",*(buf+i));
    //     }
    //     printf("\n");
    // }

    int ret = write(fd, (char *)buf, len);
    usleep(25);

    return ret;
}

int serialPort::writeBuffer_rs485(uint8_t *buf, int len)
{
    rs485_ctl(1);
    int ret = write(fd, (char *)buf, len);
    rs485_ctl(0);
    usleep(25);
    return ret;
}

void serialPort::ClosePort() { close(fd); }